using Proto;

namespace sgf.server
{
    public class BusActor : IBusActor, IOnStart, IOnRestart, IOnStop, IOnMsg
    {
        protected Dictionary<Type, Func<IContext, Task>> _msgHandlers = new();

        private Dictionary<Type, BaseMgr> _mgrs = new();

        public PID self { get; private set; }
        // private Behavior _behavior;

        public BusActor()
        {
            //     _behavior = new Behavior();
            //     _behavior.Become(Off);
        }
//
// async Task Off(IContext context)
// {
//     await Task.CompletedTask;
// }
//
// //两个状态间切换
// public async Task Receive(IContext context)
// {
//     _behavior.BecomeStacked(Receive2);
//     await Task.CompletedTask;
// }
//
// public async Task Receive2(IContext context)
// {
//     _behavior.UnbecomeStacked(); // behavior will revert back to Receive
//     await Task.CompletedTask;
// }

        async Task IActor.ReceiveAsync(IContext context)
        {
            try
            {
                // await _behavior.ReceiveAsync(context);
                switch (context.Message)
                {
                    case Started:
                        await OnStart(context);
                        self = context.Self;
                        break;
                    case Restarting:
                    {
                        await OnRestart(context);
                        break;
                    }
                    case Stopped:
                    {
                        await OnStop(context);
                        break;
                    }
                    default:
                    {
                        var messageHandler = HotfixMgr.GetMessageHandler(context.Message.GetType());
                        if (messageHandler == null) break;
                        if (context.Message is not IRequestMsg) return;
                        var task = messageHandler.Run(this, context);
                        context.ReenterAfter(task, (result =>
                        {
                            var responeMsg = result.Result;
                            if (responeMsg is NoneResponse) return;
                            context.Respond(responeMsg);
                        }));
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                LogMgr.Error("actor error: " + e.Message + e.StackTrace);
            }

            await Task.CompletedTask;
        }

        public void Stop()
        {
            self.Stop(ActorCore.Core().System());
        }

        public virtual async Task OnStart(IContext context)
        {
            LogMgr.Info($"{this.GetType().Name} OnStart");
            foreach (var onStartSystem in HotfixMgr.GetSystemTypes<IOnStartSystem>(GetType()))
            {
                await onStartSystem.Run(this, context);
            }
        }

        public virtual async Task OnRestart(IContext context)
        {
            await Task.CompletedTask;
        }

        public virtual async Task OnStop(IContext context)
        {
            await Task.CompletedTask;
        }

        public virtual async Task OnMsg(IContext context)
        {
            var type = context.Message?.GetType();
            if (type == null)
            {
                return;
            }

            if (_msgHandlers.TryGetValue(type, out var handler))
            {
                await handler(context);
            }

            await Task.CompletedTask;
        }

        protected void RegHandler(Type type, Func<IContext, Task> handler)
        {
            _msgHandlers.Add(type, handler);
        }

//UnregisterHandler
        protected void UnRegHandler(Type type)
        {
            _msgHandlers.Remove(type);
        }

        public T AddMgr<T>() where T : BaseMgr, new()
        {
            var mgr = new T
            {
                busActor = this
            };
            _mgrs.Add(typeof(T), mgr);
            mgr.Init();
            return mgr;
        }

        public async Task<T> AddMgrSync<T>() where T : BaseMgr, new()
        {
            var mgr = AddMgr<T>();
            await mgr.InitSync();
            return mgr;
        }


        public T? GetMgr<T>() where T : BaseMgr
        {
            _mgrs.TryGetValue(typeof(T), out var baseMgr);
            if (baseMgr is T mgr)
            {
                return mgr;
            }

            return null;
        }

        public T GetOrAddMgr<T>() where T : BaseMgr, new()
        {
            _mgrs.TryGetValue(typeof(T), out var baseMgr);
            if (baseMgr != null) return (baseMgr as T)!;
            return AddMgr<T>();
        }
    }
}